/*     */ package com.zimbra.cs.mime;
/*     */ 
/*     */ import com.google.common.base.Strings;
/*     */ import com.zimbra.common.localconfig.DebugConfig;
/*     */ import com.zimbra.common.mailbox.ContactConstants;
/*     */ import com.zimbra.common.mime.ContentDisposition;
/*     */ import com.zimbra.common.mime.MimeDetect;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.ByteUtil;
/*     */ import com.zimbra.common.util.CalculatorStream;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.common.zmime.ZMimeBodyPart;
/*     */ import com.zimbra.common.zmime.ZMimeMultipart;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.convert.ConversionException;
/*     */ import com.zimbra.cs.index.IndexDocument;
/*     */ import com.zimbra.cs.index.analysis.FieldTokenStream;
/*     */ import com.zimbra.cs.index.analysis.NormalizeTokenFilter;
/*     */ import com.zimbra.cs.index.analysis.RFC822AddressTokenStream;
/*     */ import com.zimbra.cs.mailbox.Contact;
/*     */ import com.zimbra.cs.mailbox.Contact.Attachment;
/*     */ import com.zimbra.cs.mailbox.Contact.DerefGroupMembersOption;
/*     */ import com.zimbra.cs.mailbox.ContactGroup;
/*     */ import com.zimbra.cs.mailbox.ContactGroup.Member.Type;
/*     */ import com.zimbra.cs.mailbox.MailServiceException;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.object.ObjectHandlerException;
/*     */ import com.zimbra.cs.util.JMSession;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Arrays;
/*     */ import java.util.HashMap;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Map.Entry;
/*     */ import javax.activation.DataHandler;
/*     */ import javax.mail.MessagingException;
/*     */ import javax.mail.internet.MimeBodyPart;
/*     */ import javax.mail.internet.MimeMessage;
/*     */ import javax.mail.internet.MimeMultipart;
/*     */ import javax.mail.internet.SharedInputStream;
/*     */ import javax.mail.util.ByteArrayDataSource;
/*     */ import javax.mail.util.SharedByteArrayInputStream;
/*     */ import org.apache.lucene.document.Document;
/*     */ import org.json.JSONException;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public final class ParsedContact
/*     */ {
/*     */   private Map<String, String> contactFields;
/*     */   private List<Contact.Attachment> contactAttachments;
/*     */   private InputStream sharedStream;
/*     */   private MimeMessage mimeMessage;
/*     */   private String digest;
/*     */   private long size;
/*     */   private List<IndexDocument> indexDocs;
/*     */   
/*     */   public ParsedContact(Map<String, ? extends Object> fields)
/*     */     throws ServiceException
/*     */   {
/*  84 */     init(fields, null);
/*     */   }
/*     */   
/*     */ 
/*     */   public ParsedContact(Map<String, ? extends Object> fields, byte[] content)
/*     */     throws ServiceException
/*     */   {
/*  91 */     InputStream in = null;
/*  92 */     if (content != null) {
/*  93 */       in = new SharedByteArrayInputStream(content);
/*     */     }
/*  95 */     init(fields, in);
/*     */   }
/*     */   
/*     */ 
/*     */   public ParsedContact(Map<String, String> fields, InputStream in)
/*     */     throws ServiceException
/*     */   {
/* 102 */     init(fields, in);
/*     */   }
/*     */   
/*     */ 
/*     */   public ParsedContact(Map<String, ? extends Object> fields, List<Contact.Attachment> attachments)
/*     */     throws ServiceException
/*     */   {
/* 109 */     init(fields, null);
/*     */     
/* 111 */     if ((attachments != null) && (!attachments.isEmpty())) {
/*     */       try {
/* 113 */         validateImageAttachments(attachments);
/* 114 */         this.contactAttachments = attachments;
/* 115 */         this.mimeMessage = generateMimeMessage(attachments);
/* 116 */         this.digest = ByteUtil.getSHA256Digest(Mime.getInputStream(this.mimeMessage), true);
/*     */         
/* 118 */         for (Contact.Attachment attach : this.contactAttachments) {
/* 119 */           this.contactFields.remove(attach.getName());
/*     */         }
/* 121 */         if (this.contactFields.isEmpty()) {
/* 122 */           throw ServiceException.INVALID_REQUEST("contact must have fields", null);
/*     */         }
/* 124 */         initializeSizeAndDigest();
/*     */       } catch (MessagingException me) {
/* 126 */         throw MailServiceException.MESSAGE_PARSE_ERROR(me);
/*     */       } catch (IOException ioe) {
/* 128 */         throw MailServiceException.MESSAGE_PARSE_ERROR(ioe);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private static void validateImageAttachments(List<Contact.Attachment> attachments) throws ServiceException, IOException {
/* 134 */     for (Contact.Attachment attach : attachments) {
/* 135 */       if (attach.getName().equals(ContactConstants.A_image)) {
/* 136 */         String contentType = MimeDetect.getMimeDetect().detect(attach.getInputStream());
/* 137 */         if ((contentType == null) || (!contentType.matches("image/.*")))
/* 138 */           throw MailServiceException.INVALID_IMAGE("Attached image is not a valid image file");
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public ParsedContact(Contact con) throws ServiceException {
/* 144 */     init(con.getAllFields(), con.getContentStream());
/*     */   }
/*     */   
/*     */   private void init(Map<String, ? extends Object> fields, InputStream in) throws ServiceException {
/* 148 */     if (fields == null) {
/* 149 */       throw ServiceException.INVALID_REQUEST("contact must have fields", null);
/*     */     }
/*     */     try
/*     */     {
/* 153 */       if ((in instanceof SharedInputStream)) {
/* 154 */         this.sharedStream = in;
/* 155 */       } else if (in != null) {
/* 156 */         byte[] content = ByteUtil.getContent(in, 1024);
/* 157 */         this.sharedStream = new SharedByteArrayInputStream(content);
/*     */       }
/*     */     } catch (IOException e) {
/* 160 */       throw MailServiceException.MESSAGE_PARSE_ERROR(e);
/*     */     }
/*     */     
/*     */ 
/* 164 */     Map<String, String> map = new HashMap();
/* 165 */     for (Map.Entry<String, ? extends Object> entry : fields.entrySet()) {
/* 166 */       String key = StringUtil.stripControlCharacters((String)entry.getKey());
/* 167 */       String value = null;
/* 168 */       if ((entry.getValue() instanceof String[])) {
/*     */         try
/*     */         {
/* 171 */           value = Contact.encodeMultiValueAttr((String[])entry.getValue());
/*     */         } catch (JSONException e) {
/* 173 */           ZimbraLog.index.warn("Error encoding multi valued attribute " + key, e);
/*     */         }
/* 175 */       } else if ((entry.getValue() instanceof String)) {
/* 176 */         value = StringUtil.stripControlCharacters((String)entry.getValue());
/* 177 */       } else if ((entry.getValue() instanceof ContactGroup)) {
/* 178 */         value = ((ContactGroup)entry.getValue()).encode();
/*     */       }
/*     */       
/* 181 */       if ((key != null) && (!key.trim().isEmpty()) && (!Strings.isNullOrEmpty(value))) {
/* 182 */         if (key.length() > 100)
/* 183 */           throw ServiceException.INVALID_REQUEST("too big filed name", null);
/* 184 */         if (value.length() > 10000000) {
/* 185 */           throw MailServiceException.CONTACT_TOO_BIG(10000000L, value.length());
/*     */         }
/* 187 */         map.put(key, value);
/*     */       }
/*     */     }
/* 190 */     if (map.isEmpty())
/* 191 */       throw ServiceException.INVALID_REQUEST("contact must have fields", null);
/* 192 */     if (map.size() > 1000) {
/* 193 */       throw ServiceException.INVALID_REQUEST("too many fields", null);
/*     */     }
/* 195 */     this.contactFields = map;
/*     */     
/*     */ 
/* 198 */     if (this.sharedStream != null) {
/* 199 */       InputStream contentStream = null;
/*     */       try
/*     */       {
/* 202 */         contentStream = getContentStream();
/* 203 */         this.contactAttachments = parseBlob(contentStream);
/* 204 */         for (Contact.Attachment attach : this.contactAttachments) {
/* 205 */           this.contactFields.remove(attach.getName());
/*     */         }
/* 207 */         initializeSizeAndDigest();
/*     */       } catch (MessagingException me) {
/* 209 */         throw MailServiceException.MESSAGE_PARSE_ERROR(me);
/*     */       } catch (IOException ioe) {
/* 211 */         throw MailServiceException.MESSAGE_PARSE_ERROR(ioe);
/*     */       } finally {
/* 213 */         ByteUtil.closeStream(contentStream);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void initializeSizeAndDigest() throws IOException {
/* 219 */     CalculatorStream calc = new CalculatorStream(getContentStream());
/* 220 */     this.size = ByteUtil.getDataLength(calc);
/* 221 */     this.digest = calc.getDigest();
/*     */   }
/*     */   
/*     */   private static MimeMessage generateMimeMessage(List<Contact.Attachment> attachments) throws MessagingException
/*     */   {
/* 226 */     MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSession());
/* 227 */     MimeMultipart multi = new ZMimeMultipart("mixed");
/* 228 */     int part = 1;
/* 229 */     for (Contact.Attachment attach : attachments) {
/* 230 */       ContentDisposition cdisp = new ContentDisposition("attachment");
/* 231 */       cdisp.setParameter("filename", attach.getFilename()).setParameter("field", attach.getName());
/*     */       
/* 233 */       MimeBodyPart bp = new ZMimeBodyPart();
/*     */       
/*     */       try
/*     */       {
/* 237 */         bp.setDataHandler(new DataHandler(new ByteArrayDataSource(attach.getContent(), attach.getContentType())));
/*     */       } catch (IOException e) {
/* 239 */         throw new MessagingException("could not generate mime part content", e);
/*     */       }
/* 241 */       bp.addHeader("Content-Disposition", cdisp.toString());
/* 242 */       bp.addHeader("Content-Type", attach.getContentType());
/* 243 */       bp.addHeader("Content-Transfer-Encoding", "8bit");
/* 244 */       multi.addBodyPart(bp);
/*     */       
/* 246 */       attach.setPartName(Integer.toString(part++));
/*     */     }
/* 248 */     mm.setContent(multi);
/* 249 */     mm.saveChanges();
/*     */     
/* 251 */     return mm;
/*     */   }
/*     */   
/*     */   private static List<Contact.Attachment> parseBlob(InputStream in) throws ServiceException, MessagingException, IOException {
/* 255 */     MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSession(), in);
/* 256 */     MimeMultipart multi = null;
/*     */     try {
/* 258 */       multi = (MimeMultipart)mm.getContent();
/*     */     } catch (ClassCastException x) {
/* 260 */       throw ServiceException.FAILURE("MimeMultipart content expected but got " + mm.getContent().toString(), x);
/*     */     }
/*     */     
/* 263 */     List<Contact.Attachment> attachments = new ArrayList(multi.getCount());
/* 264 */     for (int i = 1; i <= multi.getCount(); i++) {
/* 265 */       MimeBodyPart bp = (MimeBodyPart)multi.getBodyPart(i - 1);
/* 266 */       ContentDisposition cdisp = new ContentDisposition(bp.getHeader("Content-Disposition", null));
/*     */       
/* 268 */       Contact.Attachment attachment = new Contact.Attachment(bp.getDataHandler(), cdisp.getParameter("field"));
/* 269 */       attachment.setPartName(Integer.toString(i));
/* 270 */       attachments.add(attachment);
/*     */     }
/* 272 */     return attachments;
/*     */   }
/*     */   
/*     */   public Map<String, String> getFields() {
/* 276 */     return this.contactFields;
/*     */   }
/*     */   
/*     */   public boolean hasAttachment() {
/* 280 */     return (this.contactAttachments != null) && (!this.contactAttachments.isEmpty());
/*     */   }
/*     */   
/*     */   public List<Contact.Attachment> getAttachments() {
/* 284 */     return this.contactAttachments;
/*     */   }
/*     */   
/*     */ 
/*     */   public InputStream getContentStream()
/*     */     throws IOException
/*     */   {
/* 291 */     if (this.sharedStream != null) {
/* 292 */       return ((SharedInputStream)this.sharedStream).newStream(0L, -1L);
/*     */     }
/* 294 */     if (this.mimeMessage != null) {
/* 295 */       return Mime.getInputStream(this.mimeMessage);
/*     */     }
/* 297 */     return null;
/*     */   }
/*     */   
/*     */   public long getSize() {
/* 301 */     return this.size;
/*     */   }
/*     */   
/*     */   public String getDigest() {
/* 305 */     return this.digest;
/*     */   }
/*     */   
/*     */   public static abstract class FieldDelta {
/*     */     private final Op op;
/*     */     
/*     */     public static enum Op {
/* 312 */       ADD, 
/* 313 */       REMOVE;
/*     */       
/*     */       private Op() {}
/* 316 */       public static Op fromString(String opStr) throws ServiceException { if (opStr == null) {
/* 317 */           return null;
/*     */         }
/*     */         
/* 320 */         if ("+".equals(opStr))
/* 321 */           return ADD;
/* 322 */         if ("-".equals(opStr)) {
/* 323 */           return REMOVE;
/*     */         }
/* 325 */         throw ServiceException.INVALID_REQUEST("unknown op: " + opStr, null);
/*     */       }
/*     */     }
/*     */     
/*     */     private FieldDelta(Op op) {
/* 330 */       this.op = op;
/*     */     }
/*     */     
/*     */     Op getOp() {
/* 334 */       return this.op;
/*     */     }
/*     */   }
/*     */   
/*     */   private static class AttrDelta extends ParsedContact.FieldDelta {
/*     */     private final String name;
/*     */     private final String value;
/*     */     
/*     */     private AttrDelta(String name, String value, ParsedContact.FieldDelta.Op op) {
/* 343 */       super(null);
/* 344 */       this.name = name;
/* 345 */       this.value = value;
/*     */     }
/*     */     
/*     */     private String getName() {
/* 349 */       return this.name;
/*     */     }
/*     */     
/*     */     private String getValue() {
/* 353 */       return this.value;
/*     */     }
/*     */   }
/*     */   
/*     */   private static class GroupMemberDelta extends ParsedContact.FieldDelta {
/*     */     private final ContactGroup.Member.Type memberType;
/*     */     private final String value;
/*     */     
/*     */     private GroupMemberDelta(ContactGroup.Member.Type memberType, String value, ParsedContact.FieldDelta.Op op) {
/* 362 */       super(null);
/* 363 */       this.memberType = memberType;
/* 364 */       this.value = value;
/*     */     }
/*     */     
/*     */     private ContactGroup.Member.Type getMemberType() {
/* 368 */       return this.memberType;
/*     */     }
/*     */     
/*     */     private String getValue() {
/* 372 */       return this.value;
/*     */     }
/*     */   }
/*     */   
/*     */   public static class FieldDeltaList {
/* 377 */     private final List<ParsedContact.FieldDelta> deltaList = new ArrayList();
/*     */     
/*     */     public void addAttrDelta(String name, String value, ParsedContact.FieldDelta.Op op)
/*     */     {
/* 381 */       if ((name == null) || (name.trim().equals(""))) {
/* 382 */         return;
/*     */       }
/* 384 */       this.deltaList.add(new ParsedContact.AttrDelta(name, value, op, null));
/*     */     }
/*     */     
/*     */     public void addGroupMemberDelta(ContactGroup.Member.Type memberType, String value, ParsedContact.FieldDelta.Op op) {
/* 388 */       this.deltaList.add(new ParsedContact.GroupMemberDelta(memberType, value, op, null));
/*     */     }
/*     */     
/*     */     private List<ParsedContact.FieldDelta> getDeltaList() {
/* 392 */       return this.deltaList;
/*     */     }
/*     */     
/*     */     private void removeAllAttrDeltaByName(String name) {
/* 396 */       for (Iterator<ParsedContact.FieldDelta> iter = this.deltaList.iterator(); iter.hasNext();) {
/* 397 */         ParsedContact.FieldDelta delta = (ParsedContact.FieldDelta)iter.next();
/* 398 */         if ((delta instanceof ParsedContact.AttrDelta)) {
/* 399 */           ParsedContact.AttrDelta attrDelta = (ParsedContact.AttrDelta)delta;
/* 400 */           if (ParsedContact.AttrDelta.access$300(attrDelta).equals(name)) {
/* 401 */             iter.remove();
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public ParsedContact modifyField(String name, String newValue) {
/* 409 */     if (Strings.isNullOrEmpty(newValue)) {
/* 410 */       this.contactFields.remove(name);
/*     */     } else
/* 412 */       this.contactFields.put(name, newValue);
/* 413 */     return this;
/*     */   }
/*     */   
/*     */   public ParsedContact modify(Map<String, String> fieldDelta, List<Contact.Attachment> attachDelta)
/*     */     throws ServiceException
/*     */   {
/* 419 */     FieldDeltaList fieldDeltaList = new FieldDeltaList();
/*     */     
/* 421 */     for (Map.Entry<String, String> entry : fieldDelta.entrySet()) {
/* 422 */       fieldDeltaList.addAttrDelta((String)entry.getKey(), (String)entry.getValue(), null);
/*     */     }
/*     */     
/* 425 */     return modify(fieldDeltaList, attachDelta);
/*     */   }
/*     */   
/*     */   public ParsedContact modify(FieldDeltaList fieldDeltaList, List<Contact.Attachment> attachDelta) throws ServiceException
/*     */   {
/* 430 */     return modify(fieldDeltaList, attachDelta, false);
/*     */   }
/*     */   
/*     */   public ParsedContact modify(FieldDeltaList fieldDeltaList, List<Contact.Attachment> attachDelta, boolean discardExistingMembers) throws ServiceException
/*     */   {
/* 435 */     if ((attachDelta != null) && (!attachDelta.isEmpty())) {
/*     */       try {
/* 437 */         validateImageAttachments(attachDelta);
/*     */       } catch (IOException ioe) {
/* 439 */         throw MailServiceException.MESSAGE_PARSE_ERROR(ioe);
/*     */       }
/* 441 */       for (Contact.Attachment attach : attachDelta)
/*     */       {
/* 443 */         fieldDeltaList.removeAllAttrDeltaByName(attach.getName());
/*     */         
/*     */ 
/* 446 */         removeAttachment(attach.getName());
/* 447 */         if (this.contactAttachments == null) {
/* 448 */           this.contactAttachments = new ArrayList(attachDelta.size());
/*     */         }
/* 450 */         this.contactAttachments.add(attach);
/*     */       }
/*     */     }
/*     */     
/* 454 */     ContactGroup contactGroup = null;
/* 455 */     String encodedContactGroup = (String)this.contactFields.get(ContactConstants.A_groupMember);
/* 456 */     contactGroup = encodedContactGroup == null ? ContactGroup.init() : ContactGroup.init(encodedContactGroup);
/*     */     
/*     */ 
/* 459 */     boolean contactGroupMemberChanged = false;
/* 460 */     if ((discardExistingMembers) && (contactGroup.hasMembers())) {
/* 461 */       contactGroup.removeAllMembers();
/* 462 */       contactGroupMemberChanged = true;
/*     */     }
/* 464 */     for (FieldDelta delta : fieldDeltaList.getDeltaList()) {
/* 465 */       if ((delta instanceof AttrDelta)) {
/* 466 */         processAttrDelta((AttrDelta)delta);
/* 467 */       } else if ((delta instanceof GroupMemberDelta)) {
/* 468 */         processGroupMemberDelta((GroupMemberDelta)delta, contactGroup);
/* 469 */         contactGroupMemberChanged = true;
/*     */       }
/*     */     }
/*     */     
/* 473 */     if (this.contactFields.isEmpty()) {
/* 474 */       throw ServiceException.INVALID_REQUEST("contact must have fields", null);
/*     */     }
/* 476 */     if (contactGroupMemberChanged) {
/* 477 */       this.contactFields.put(ContactConstants.A_groupMember, contactGroup.encode());
/*     */     }
/*     */     
/* 480 */     this.digest = null;
/* 481 */     this.indexDocs = null;
/*     */     
/* 483 */     if (this.contactAttachments != null) {
/*     */       try {
/* 485 */         this.mimeMessage = generateMimeMessage(this.contactAttachments);
/*     */         
/*     */ 
/* 488 */         ByteUtil.closeStream(this.sharedStream);
/* 489 */         this.sharedStream = null;
/*     */         
/* 491 */         initializeSizeAndDigest();
/*     */       } catch (MessagingException me) {
/* 493 */         throw MailServiceException.MESSAGE_PARSE_ERROR(me);
/*     */       } catch (IOException e) {
/* 495 */         throw MailServiceException.MESSAGE_PARSE_ERROR(e);
/*     */       }
/*     */     }
/*     */     else {
/* 499 */       ByteUtil.closeStream(this.sharedStream);
/* 500 */       this.sharedStream = null;
/* 501 */       this.mimeMessage = null;
/* 502 */       this.size = 0L;
/* 503 */       this.digest = null;
/*     */     }
/*     */     
/* 506 */     return this;
/*     */   }
/*     */   
/*     */   private void processAttrDelta(AttrDelta delta) throws ServiceException
/*     */   {
/* 511 */     String name = StringUtil.stripControlCharacters(delta.getName());
/* 512 */     if ((name == null) || (name.trim().equals(""))) {
/* 513 */       return;
/*     */     }
/*     */     
/* 516 */     removeAttachment(name);
/*     */     
/* 518 */     String newValue = StringUtil.stripControlCharacters(delta.getValue());
/* 519 */     ParsedContact.FieldDelta.Op op = delta.getOp();
/*     */     
/* 521 */     if (op == null)
/*     */     {
/* 523 */       if ((newValue == null) || (newValue.equals(""))) {
/* 524 */         this.contactFields.remove(name);
/*     */       } else {
/* 526 */         this.contactFields.put(name, newValue);
/*     */       }
/* 528 */       return;
/*     */     }
/*     */     
/*     */ 
/* 532 */     if ((newValue == null) || (newValue.equals(""))) {
/* 533 */       throw ServiceException.INVALID_REQUEST("adding or removing empty value is not allowed", null);
/*     */     }
/*     */     
/* 536 */     String curValue = (String)this.contactFields.get(name);
/*     */     
/* 538 */     if (curValue == null) {
/* 539 */       if (op != ParsedContact.FieldDelta.Op.REMOVE)
/*     */       {
/*     */ 
/* 542 */         this.contactFields.put(name, newValue);
/*     */       }
/*     */     }
/*     */     else {
/* 546 */       List<String> curValuesList = null;
/*     */       try {
/* 548 */         curValuesList = new ArrayList(Arrays.asList(Contact.parseMultiValueAttr(curValue)));
/*     */       }
/*     */       catch (JSONException e) {
/* 551 */         ZimbraLog.misc.warn("unable to modify contact for: field=" + name + ", value=" + newValue + ", op=" + op.name() + ".  delta entry ignored", e); return;
/*     */       }
/*     */       
/*     */ 
/*     */       Iterator<String> iter;
/*     */       
/* 557 */       if (op == ParsedContact.FieldDelta.Op.REMOVE)
/*     */       {
/* 559 */         for (iter = curValuesList.iterator(); iter.hasNext();) {
/* 560 */           if (newValue.equals(iter.next())) {
/* 561 */             iter.remove();
/*     */           }
/*     */         }
/*     */       }
/*     */       else {
/* 566 */         if (curValuesList.contains(newValue)) {
/* 567 */           return;
/*     */         }
/* 569 */         curValuesList.add(newValue);
/*     */       }
/*     */       
/*     */ 
/* 573 */       if (curValuesList.size() > 0)
/*     */       {
/* 575 */         String[] newValues = (String[])curValuesList.toArray(new String[curValuesList.size()]);
/* 576 */         String newMultiValues = null;
/*     */         try {
/* 578 */           newMultiValues = Contact.encodeMultiValueAttr(newValues);
/*     */         }
/*     */         catch (JSONException e) {
/* 581 */           ZimbraLog.misc.warn("unable to modify contact for: field=" + name + ", value=" + newValue + ", op=" + op.name() + ".  delta entry ignored", e);
/*     */           
/*     */ 
/* 584 */           return;
/*     */         }
/*     */         
/*     */ 
/* 588 */         this.contactFields.put(name, newMultiValues);
/*     */       } else {
/* 590 */         this.contactFields.remove(name);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void processGroupMemberDelta(GroupMemberDelta delta, ContactGroup contactGroup)
/*     */     throws ServiceException
/*     */   {
/* 598 */     ParsedContact.FieldDelta.Op op = delta.getOp();
/* 599 */     ContactGroup.Member.Type memberType = delta.getMemberType();
/* 600 */     String value = delta.getValue();
/*     */     
/* 602 */     if (op == ParsedContact.FieldDelta.Op.ADD) {
/* 603 */       contactGroup.addMember(memberType, value);
/* 604 */     } else if (op == ParsedContact.FieldDelta.Op.REMOVE) {
/* 605 */       contactGroup.removeMember(memberType, value);
/*     */     }
/*     */   }
/*     */   
/*     */   private void removeAttachment(String name) {
/* 610 */     if (this.contactAttachments == null) {
/* 611 */       return;
/*     */     }
/* 613 */     for (Iterator<Contact.Attachment> it = this.contactAttachments.iterator(); it.hasNext();) {
/* 614 */       if (((Contact.Attachment)it.next()).getName().equals(name)) {
/* 615 */         it.remove();
/*     */       }
/*     */     }
/* 618 */     if (this.contactAttachments.isEmpty()) {
/* 619 */       this.contactAttachments = null;
/*     */     }
/*     */   }
/*     */   
/*     */   public ParsedContact analyze(Mailbox mbox) throws ServiceException
/*     */   {
/*     */     try {
/* 626 */       analyzeContact(mbox.getAccount(), mbox.attachmentsIndexingEnabled());
/*     */     } catch (ServiceException e) {
/* 628 */       throw e;
/*     */     } catch (Exception e) {
/* 630 */       ZimbraLog.index.warn("exception while analyzing contact; attachments will be partially indexed", e);
/*     */     }
/* 632 */     return this;
/*     */   }
/*     */   
/* 635 */   boolean mHasTemporaryAnalysisFailure = false;
/* 636 */   public boolean hasTemporaryAnalysisFailure() { return this.mHasTemporaryAnalysisFailure; }
/*     */   
/*     */   private void analyzeContact(Account acct, boolean indexAttachments) throws ServiceException {
/* 639 */     if (this.indexDocs != null) {
/* 640 */       return;
/*     */     }
/* 642 */     this.indexDocs = new ArrayList();
/* 643 */     StringBuilder attachContent = new StringBuilder();
/*     */     
/* 645 */     ServiceException conversionError = null;
/* 646 */     if (this.contactAttachments != null) {
/* 647 */       for (Contact.Attachment attach : this.contactAttachments) {
/*     */         try {
/* 649 */           analyzeAttachment(attach, attachContent, indexAttachments);
/*     */         } catch (MimeHandlerException e) {
/* 651 */           String part = attach.getPartName();
/* 652 */           String ctype = attach.getContentType();
/* 653 */           ZimbraLog.index.warn("Parse error on attachment " + part + " (" + ctype + ")", e);
/* 654 */           if ((conversionError == null) && (ConversionException.isTemporaryCauseOf(e))) {
/* 655 */             conversionError = ServiceException.FAILURE("failed to analyze part", e.getCause());
/* 656 */             this.mHasTemporaryAnalysisFailure = true;
/*     */           }
/*     */         } catch (ObjectHandlerException e) {
/* 659 */           String part = attach.getPartName();
/* 660 */           String ctype = attach.getContentType();
/* 661 */           ZimbraLog.index.warn("Parse error on attachment " + part + " (" + ctype + ")", e);
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 666 */     this.indexDocs.add(getPrimaryDocument(acct, attachContent.toString()));
/*     */   }
/*     */   
/*     */   public List<IndexDocument> getLuceneDocuments(Mailbox mbox) throws ServiceException {
/* 670 */     analyze(mbox);
/* 671 */     return this.indexDocs;
/*     */   }
/*     */   
/*     */   private void analyzeAttachment(Contact.Attachment attach, StringBuilder contentText, boolean indexAttachments) throws MimeHandlerException, ObjectHandlerException, ServiceException
/*     */   {
/* 676 */     String ctype = attach.getContentType();
/* 677 */     MimeHandler handler = MimeHandlerManager.getMimeHandler(ctype, attach.getFilename());
/* 678 */     assert (handler != null);
/*     */     
/* 680 */     if (handler.isIndexingEnabled()) {
/* 681 */       handler.init(attach);
/* 682 */       handler.setPartName(attach.getPartName());
/* 683 */       handler.setFilename(attach.getFilename());
/* 684 */       handler.setSize(attach.getSize());
/*     */       
/* 686 */       if ((indexAttachments) && (!DebugConfig.disableIndexingAttachmentsTogether))
/*     */       {
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 693 */         contentText.append(contentText.length() == 0 ? "" : " ").append(handler.getContent());
/*     */       }
/*     */       
/* 696 */       if ((indexAttachments) && (!DebugConfig.disableIndexingAttachmentsSeparately))
/*     */       {
/*     */ 
/*     */ 
/*     */ 
/* 701 */         Document doc = handler.getDocument();
/* 702 */         if (doc != null) {
/* 703 */           IndexDocument idoc = new IndexDocument(doc);
/* 704 */           idoc.addSortSize(attach.getSize());
/* 705 */           this.indexDocs.add(idoc);
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private static void appendContactField(StringBuilder sb, ParsedContact contact, String fieldName) {
/* 712 */     String value = (String)contact.getFields().get(fieldName);
/* 713 */     if (!Strings.isNullOrEmpty(value)) {
/* 714 */       sb.append(NormalizeTokenFilter.normalize(value)).append(' ');
/*     */     }
/*     */   }
/*     */   
/*     */   private IndexDocument getPrimaryDocument(Account acct, String contentStrIn) throws ServiceException
/*     */   {
/* 720 */     StringBuilder contentText = new StringBuilder();
/*     */     
/* 722 */     String[] emailFields = Contact.getEmailFields(acct);
/*     */     
/* 724 */     FieldTokenStream fields = new FieldTokenStream();
/* 725 */     for (Map.Entry<String, String> entry : getFields().entrySet()) {
/* 726 */       String fieldName = (String)entry.getKey();
/*     */       
/*     */ 
/* 729 */       if ((!Contact.isSMIMECertField(fieldName)) && (!ContactConstants.A_member.equals(fieldName)) && (!ContactConstants.A_groupMember.equals(fieldName)))
/*     */       {
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 735 */         if ((!Contact.isEmailField(emailFields, fieldName)) && 
/* 736 */           (!ContactConstants.A_fileAs.equalsIgnoreCase(fieldName))) {
/* 737 */           contentText.append((String)entry.getValue()).append(' ');
/*     */         }
/* 739 */         fields.add(fieldName, (String)entry.getValue());
/*     */       }
/*     */     }
/*     */     
/*     */ 
/* 744 */     StringBuilder emails = new StringBuilder();
/* 745 */     for (String email : Contact.getEmailAddresses(emailFields, getFields(), Contact.DerefGroupMembersOption.NONE)) {
/* 746 */       emails.append(email).append(',');
/*     */     }
/*     */     
/* 749 */     RFC822AddressTokenStream to = new RFC822AddressTokenStream(emails.toString());
/* 750 */     String emailStrTokens = StringUtil.join(" ", to.getAllTokens());
/*     */     
/* 752 */     StringBuilder searchText = new StringBuilder(emailStrTokens).append(' ');
/* 753 */     appendContactField(searchText, this, ContactConstants.A_company);
/* 754 */     appendContactField(searchText, this, ContactConstants.A_phoneticCompany);
/* 755 */     appendContactField(searchText, this, ContactConstants.A_firstName);
/* 756 */     appendContactField(searchText, this, ContactConstants.A_phoneticFirstName);
/* 757 */     appendContactField(searchText, this, ContactConstants.A_lastName);
/* 758 */     appendContactField(searchText, this, ContactConstants.A_phoneticLastName);
/* 759 */     appendContactField(searchText, this, ContactConstants.A_nickname);
/* 760 */     appendContactField(searchText, this, ContactConstants.A_fullName);
/*     */     
/*     */ 
/*     */ 
/*     */ 
/* 765 */     contentText = new StringBuilder(emailStrTokens).append(' ').append(contentText).append(' ').append(contentStrIn);
/*     */     
/* 767 */     IndexDocument doc = new IndexDocument();
/*     */     
/*     */ 
/* 770 */     doc.addTo(to);
/*     */     
/*     */ 
/* 773 */     doc.addFrom(new RFC822AddressTokenStream(Contact.getFileAsString(this.contactFields)));
/*     */     
/* 775 */     doc.addContactData(searchText.toString());
/* 776 */     doc.addContent(contentText.toString());
/* 777 */     doc.addPartName("CONTACT");
/*     */     
/*     */ 
/* 780 */     doc.addField(fields);
/*     */     
/* 782 */     return doc;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mime/ParsedContact.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */